package kayao.client.scene;

import java.util.Vector;
import kayao.client.data.SharedMemory;
import kayao.client.data.Subscriber;
import kayao.client.network.message.MessageHandler;
import kayao.client.network.message.SubscriptionRequestMessage;
import kayao.common.KayaoValues;

public abstract class AoIManager 
{
	protected static Vector<Subscriber> mSubscribers;
	protected static Object mAoILock;
	protected static int mKingdom;
	protected static Vector<Integer> slaves=null;
	protected static String[] mKings = new String[KayaoValues.NUMBER_OF_KINGDOMS];
	
	
	public static void initialize()
	{
		mKingdom=-1;
		mSubscribers= new Vector<Subscriber>();
		mAoILock=new Object();
	}

	public static void reset() {
		mSubscribers=new Vector<Subscriber>();
		slaves=null;
		mKingdom=-1;
	}

	//***********************************************************
	//STUFF ABOUT SUBSCRIPTIONS
	//***********************************************************
	
	public static void printSubscribers(){
		System.out.println("!!PrintSubscribers");
		for(int i=0; i<mSubscribers.size(); i++){
			System.out.println("!! "+mSubscribers.get(i).toString());
		}
		System.out.println("!!------------------------------");
	}

	public static void updateSubscriberInKingdom(Vector<Integer> subscribers, int kingdom)
	{
		synchronized(mAoILock){
		System.out.println("(AoIManager.updateSubscriberList) newlist: "+subscribers.size()+" oldlist: "+mSubscribers.size());
		
		//for each new suscriber,or we add the kingdom or we add the suscriber
		for(int i: subscribers){
			boolean newSubscriber = true;
			for(Subscriber s: mSubscribers){
				if(s.getId()==i)
				{
					s.addKingdom(kingdom);
					System.out.println("[AoIManager] - New kingdom: " + kingdom+" added to subscriber id:" + s.getId());
					newSubscriber = false;
					break;
				}
			}
			if(newSubscriber)
			{
				System.out.println("[AoIManager] - New suscriber with id: "+i +" created in kingdom: " + kingdom);
				mSubscribers.add(new Subscriber(i, kingdom));
			}
				
		}
		//for each old suscriber, we remove the kingdom if it's not anymore
		for(Subscriber s: mSubscribers){
			boolean referred = false;
			for(int i: subscribers){
				if(s.getId()==i)
				{
					referred = true;
					break;
				}
			}
			if(!referred)
			{
				s.removeKingdom(kingdom);
				if(s.isEmpty()){
					System.out.println("(AoIManager.updateSubscriberList) subscriber: "+s.getId()+" removed");
					mSubscribers.remove(s);
				}
			}
		}
		}
	}

	public static Vector<Subscriber> getSubscribers(){
		synchronized(mAoILock){
			return mSubscribers;
		}
	}

	
	// Insert messages to send to Kings
	public static void sendSubscriptionRequests(){
		synchronized(mAoILock){
		int i=0;
		for(String ip:mKings){
			if(ip==null){
				i++;
				continue;
			}
			if(!ip.equals(SharedMemory.getInstance().getMyself().getIP())) {	// Don't send to myself...
				MessageHandler.insertOutgoingMessage(new SubscriptionRequestMessage(ip,2000,i));
			}
			i++;
		}
		}
	}

	public static void sendLaterSubscriptionRequest(String ip, int kingdom){
		synchronized(mAoILock){
		if(!ip.equals(SharedMemory.getInstance().getMyself().getIP())) {
			// Don't send to myself...
			MessageHandler.insertAwaitingResponseMessage(new SubscriptionRequestMessage(ip,5000, kingdom));
		}
		}
	}


	//***********************************************************
	//STUFF ABOUT KINGS
	//***********************************************************

	// My kings are kept in a list
	public static String[] getMyKings(){
		synchronized(mAoILock){
			return mKings;
		}
	}
	public static void removeSlave(int client) {
		synchronized(mAoILock){
		//check if we're king?
		if(mKingdom==-1)
		{
			System.out.println("[AoIManager] - Trying to remove an slave not being a king, return!.");
			return;
		}
		
		//remove from slavelist
		for(int i=0;i<slaves.size();i++){
			if(slaves.get(i)==client){
				slaves.remove(i);
				System.out.println("[AoIManager] - Removing id: " + client + " from slaves list.");
			}
		}
		
		//remove in our kingdom in subscribers
		for(int i=0;i<mSubscribers.size();i++){
			if(mSubscribers.get(i).getId()==client)
			{
				mSubscribers.get(i).removeKingdom(mKingdom);
				System.out.println("[AoIManager] - Removing id: " + client + " from subscribers list.");
				if(mSubscribers.get(i).isEmpty())
				{
					mSubscribers.remove(i);
					System.out.println("[AoIManager] - Deleting guy id: " + client + " not interested in more kingdoms.");
				}
			}
		}
		}
	}
	public static void addSlave(int id) {
		synchronized(mAoILock){
		if(mKingdom==-1)
		{
			System.out.println("[AoIManager] - Trying to add a slave not being a king, return!.");
			return;
		}
		
		//add as slave if it doesn't exist
		boolean exists=false;
		for(int i=0;i<slaves.size();i++)
			if(slaves.get(i)==id)
				exists=true;
		if(!exists)
		{
			slaves.add(id);
			System.out.println("[AoIManager] - New slave! id: "+ id);
		}
			
		//add as subscriber
		if(id==SharedMemory.getInstance().getMyself().getId())
			return;
		exists=false;
		for(int i=0;i<mSubscribers.size();i++){
			if(mSubscribers.get(i).getId()==id)
			{
				System.out.println("[AoIManager] - Adding a kingdom for subscriber id: "+ id + ", kingdom: " + mKingdom);
				mSubscribers.get(i).addKingdom((int)mKingdom);
				exists=true;
			}
		}
		if(!exists)
		{
			System.out.println("[AoIManager] - Creating subscriber id: " + id + ", in kingdom: "+ mKingdom);
			mSubscribers.add(new Subscriber(id, mKingdom));
		}
		printSubscribers();
		}
	}

	public static boolean amIKingInRegion(int region) {
		synchronized(mAoILock){
			try {
				if(mKings[region]==null){
					System.out.println("[AoIManager] amIKingInRegion: (null) false");
					return false;
				}
				else if(mKings[region].equals(SharedMemory.getInstance().getMyself().getIP())){
					System.out.println("[AoIManager] amIKingInRegion: true");
					return true;
				} else {
					System.out.println("[AoIManager] amIKingInRegion: false");
					return false;
				}
			} catch (ArrayIndexOutOfBoundsException e){
				System.out.println("[AoIManager] EXCEPTION amIKingInRegion region: "+region);
				e.printStackTrace();
			}
		}
		System.out.println("[AoIManager] amIKingInRegion: false");
		return false;
	}

	static String getKingByID(int i){
		synchronized(mAoILock){
		return mKings[i];
		}
	}

	public static void printKingInfo(String from){
		System.out.println("[AoIManager] - KingInfo from: "+from);
		for(int i=0; i<mKings.length; i++){
			System.out.println("!region "+i+" king: "+mKings[i]);
		}
		System.out.println("!-----------------------");
	}
	
	public static boolean updateMyKings(String[] kings){
		synchronized(mAoILock){
		boolean changes=false;
		for(int i = 0; i<mKings.length; i++){
			if(mKings[i]==null && kings[i]==null)
				continue;
			else if(mKings[i]!=null && kings[i]==null)
			{
				changes=true;
				break;
			}
			else if(mKings[i]==null && kings[i]!=null)
			{
				changes=true;
				break;
			}
			else if(!mKings[i].equals(kings[i])){
				changes=true;
				break;
			}
		}
		mKings = kings;
		return changes;
		}
	}
	public static void removeKingFromIp(String kingIp) {
		synchronized(mAoILock){
		for(int i = 0; i<mKings.length; i++){
			if(mKings[i]!=null && mKings[i].equals(kingIp)){
				mKings[i]=null;
				if(kingIp.equals(SharedMemory.getInstance().getMyself().getIP()))
				{
					mKingdom=-1;
					slaves=null;
				}
				break;
			}
		}
		}
	}

	public static void putMeAsKing(Integer kingdom) 
	{
		synchronized(mAoILock){
		mKings[kingdom]=SharedMemory.getInstance().getMyself().getIP();
		mKingdom=(byte)kingdom.intValue();
		System.out.println("[AoIManager] - I'm my own king in region: " + kingdom);
		
		//slaves list
		slaves=new Vector<Integer>();
		//slaves.add(SharedMemory.getInstance().getMyself().getId());
		}
		addSlave(SharedMemory.getInstance().getMyself().getId());
	}

	public static int getKingdomFromIP(String ip) {
		synchronized(mAoILock){
			for(int i = 0; i<mKings.length; i++){
				if(mKings[i]!=null && mKings[i].equals(ip)){
					return i;
				}
			}
			System.out.println("%[AoIManager] Looking for a king with ip: "+ip+" Kingdom -1");
			//printKingInfo("AoI.getKingdomFromIP()");
			return -1;
		}
	}
	public static Vector<Integer> getSlavesList() {
		return slaves;
	}

	public static void removeKingdom(int kingdom) {

		for(int i=0;i<mSubscribers.size();i++)
		{
			synchronized(mAoILock){
			mSubscribers.get(i).removeKingdom(kingdom);
			System.out.println("Removing interest of client id: "+ mSubscribers.get(i).getId() + " from kingdom "+ kingdom);
			if(mSubscribers.get(i).isEmpty())
			{
				System.out.println("Deleting client id: "+ mSubscribers.get(i).getId() + " from subscribers list.");
				mSubscribers.remove(i);
			}
			}
		}
		
	}
}
